#ifndef UTILS_HPP
#define UTILS_HPP

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <mpi.h>

// 外迭代精度
#ifndef KSPBIT
#define KSPBIT 64
#endif

// 预条件精度
#ifndef PCBIT
#define PCBIT 64
#endif

#if KSPBIT == 64
typedef double ksp_t;
#elif KSPBIT == 32
typedef float ksp_t;
#endif

#if PCBIT == 64
typedef double pc_t;
#elif PCBIT == 32
typedef float pc_t;
#endif

/// @brief  读取二进制文件
/// @param buf 目标缓冲区
/// @param filename 文件名 
/// @param size_of_elems 每个元素的大小/字节
/// @param start 起始位置
/// @param nums 读取的元素个数
/// @return 实际读取的元素个数
int read_binary(void * buf, const char * filename, int size_of_elems, long long start, int nums) {
    assert(size_of_elems == 4 || size_of_elems == 8);
    int my_pid; MPI_Comm_rank(MPI_COMM_WORLD, &my_pid);
    if (my_pid == 0) printf("reading binary from %s\n", filename);

    // 打开文件
    FILE * fp = fopen(filename, "rb");
    if (fp == NULL) {
        printf("cannot open %s \n", filename);
        return -1;
    }
    // 移动文件指针
    if (fseek(fp, size_of_elems * start, SEEK_SET) != 0) {
        printf("Error! cannot move file pointer to %d-th bytes\n", size_of_elems * start);
        fclose(fp);
        return -1;
    }
    // 读取数据
    int ret = fread(buf, size_of_elems, nums, fp);
    return ret;
}

/// @brief 检查输入是否合法
/// @param input 输入数组
/// @param num 输入数组的长度
void check_input(const double * input, int num) {
    for (int i = 0; i < num; i++)
        // assert(input[i] == input[i]);
        assert(abs(input[i]) < 1e20);
}

#endif // UTILS_HPP